package com.gitee.wsl.config

import com.gitee.wsl.config.pref.*
import com.gitee.wsl.config.pref.IntPref
import com.gitee.wsl.config.pref.StringNullablePref
import com.gitee.wsl.config.pref.StringPref
import com.gitee.wsl.data.store.StoreServer
import kotlin.reflect.KProperty

 abstract class AbstractConfigModel(val storeServer: StoreServer,
                                    val keyMap:(Int)->String={"key_$it"},
                                    val kotprefProperties: MutableMap<String, PreferenceProperty> = mutableMapOf()
     ):MutableMap<String, PreferenceProperty> by kotprefProperties{

     internal var kotprefInTransaction: Boolean = false

     /**
     * Preference file name
     */
     var configName : String = this::class.simpleName.toString()

     /**
      * commit() all properties in this pref by default instead of apply()
      */
     open val commitAllPropertiesByDefault: Boolean = false
     
     /**
      * Delegate string shared preferences property.
      * @param default default string value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun stringPref(
         default: String = "",
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<String> = StringPref(default, key, commitByDefault)

     /**
      * Delegate string shared preferences property.
      * @param default default string value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun stringPref(
         default: String = "",
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<String> =
         stringPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate nullable string shared preferences property.
      * @param default default string value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun nullableStringPref(
         default: String? = null,
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<String?> =
         StringNullablePref(default, key, commitByDefault)

     /**
      * Delegate nullable string shared preferences property.
      * @param default default string value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun nullableStringPref(
         default: String? = null,
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<String?> =
         nullableStringPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate int shared preferences property.
      * @param default default int value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun intPref(
         default: Int = 0,
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Int> = IntPref(default, key, commitByDefault)

     /**
      * Delegate int shared preferences property.
      * @param default default int value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun intPref(
         default: Int = 0,
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Int> =
         intPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate long shared preferences property.
      * @param default default long value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun longPref(
         default: Long = 0L,
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Long> = LongPref(default, key, commitByDefault)

     /**
      * Delegate long shared preferences property.
      * @param default default long value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun longPref(
         default: Long = 0L,
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Long> = longPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate float shared preferences property.
      * @param default default float value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun floatPref(
         default: Float = 0F,
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Float> = FloatPref(default, key, commitByDefault)

     /**
      * Delegate float shared preferences property.
      * @param default default float value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun floatPref(
         default: Float = 0F,
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Float> = floatPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate boolean shared preferences property.
      * @param default default boolean value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */
     protected fun booleanPref(
         default: Boolean = false,
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Boolean> = BooleanPref(default, key, commitByDefault)

     /**
      * Delegate boolean shared preferences property.
      * @param default default boolean value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */
     protected fun booleanPref(
         default: Boolean = false,
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractPref<Boolean> = booleanPref(default, keyMap.invoke(key), commitByDefault)

     /**
      * Delegate string set shared preferences property.
      * @param default default string set value
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      */

     protected fun stringSetPref(
         default: Set<String> = LinkedHashSet(),
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractStringSetPref = stringSetPref(key, commitByDefault) { default }

     /**
      * Delegate string set shared preferences property.
      * @param default default string set value
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      */

     protected fun stringSetPref(
         default: Set<String> = LinkedHashSet<String>(),
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault
     ): AbstractStringSetPref = stringSetPref(keyMap.invoke(key), commitByDefault) { default }

     /**
      * Delegate string set shared preferences property.
      * @param key custom preferences key
      * @param commitByDefault commit this property instead of apply
      * @param default default string set value creation function
      */

     protected fun stringSetPref(
         key: String? = null,
         commitByDefault: Boolean = commitAllPropertiesByDefault,
         default: () -> Set<String>
     ): AbstractStringSetPref = StringSetPref(default, key, commitByDefault)

     /**
      * Delegate string set shared preferences property.
      * @param key custom preferences key resource id
      * @param commitByDefault commit this property instead of apply
      * @param default default string set value
      */
     protected fun stringSetPref(
         key: Int,
         commitByDefault: Boolean = commitAllPropertiesByDefault,
         default: () -> Set<String>
     ): AbstractStringSetPref = stringSetPref(keyMap.invoke(key), commitByDefault, default)



     /**
      * Get preference key for a property.
      * @param property property delegated to Kotpref
      * @return preference key
      */
     fun getPrefKey(property: KProperty<*>): String? {
         return kotprefProperties[property.name]?.preferenceKey
     }

     /**
      * Remove entry from SharedPreferences
      * @param property property to remove
      */
     fun remove(property: KProperty<*>) {
         getPrefKey(property)?.let {
             storeServer.remove(it)
         }
     }
 }